package com.syt.mina.filter.codec.flex;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.zip.Deflater;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;

import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf3Output;

public class AMF3Encoder implements ProtocolEncoder {
	private Log log = LogFactory.getLog(AMF3Encoder.class);
	private static int cachesize = 1024;
	private final AttributeKey DEFLATER = new AttributeKey(getClass(), "deflater");	
	public static long totalLength = 0;
	//private final Amf3Output amf3out;
	private final SerializationContext context;
	
	public AMF3Encoder() {
		// TODO Auto-generated constructor stub	
		context = new SerializationContext();
		//amf3out = new Amf3Output(context);
	}

	public void dispose(IoSession session) throws Exception {
		// TODO Auto-generated method stub
		//amf3out.close();
	}

	public void encode(IoSession session, Object message,
			ProtocolEncoderOutput out) throws Exception {
		// TODO Auto-generated method stub
		IoBuffer buffer;
		if(message instanceof String){
			byte[] bytes = ((String)message).getBytes("UTF-8");
			buffer = IoBuffer.allocate(bytes.length+1);
			buffer.put(bytes);
			buffer.put((byte)0x0);
			buffer.flip();
			out.write(buffer);
		}else {
			synchronized(session) {
				Amf3Output amf3out = new Amf3Output(context);
				Map map = (Map)message;
				ByteArrayOutputStream stream = new ByteArrayOutputStream();
				amf3out.setOutputStream(stream);
				amf3out.writeObject(map);		
				amf3out.flush();
				//byte bytes[] = compress(session,stream.toByteArray());
				byte bytes[] = stream.toByteArray();
				totalLength = totalLength + bytes.length;
				log.info("total length " + totalLength);
				byte[] header = int2Bytes(bytes.length);
				buffer = IoBuffer.allocate(bytes.length + header.length, false);
				byte[] perfect = new byte[bytes.length + header.length];
				System.arraycopy(header, 0, perfect, 0, header.length);
				System.arraycopy(bytes, 0, perfect, header.length, bytes.length);
				buffer.put(perfect);
				buffer.flip();
				out.write(buffer);
				buffer.free();
			}
		}			
	}
	
	private byte[] int2Bytes(int i) {
			byte[] targets = new byte[4];
			targets[3] = (byte) (i % 256);// 最低位 
			targets[2] = (byte) ((i >> 8) % 256);// 次低位 
			targets[1] = (byte) ((i >> 16) % 256);// 次高位 
			targets[0] = (byte) ((i >> 24)%256) ;// 最高位,无符号右移。 
			return targets; 
	}
	
	private byte[] compress(IoSession session,byte[] inputs){
		Deflater deflater = (Deflater)session.getAttribute(DEFLATER);
		if(deflater == null){
			deflater = new Deflater();
			session.setAttribute(DEFLATER,deflater);
		}
		deflater.reset();
		deflater.setInput(inputs);
		deflater.finish();
		byte outputs[] = new byte[0]; 
		ByteArrayOutputStream stream = new ByteArrayOutputStream(inputs.length); 
		byte[] bytes = new byte[cachesize];
		int value; 
		while(!deflater.finished()){
			value = deflater.deflate(bytes);
			stream.write(bytes,0, value);			
		}
		outputs = stream.toByteArray();
		try {
			stream.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return outputs;
	}
	

}
